/**
*	Nikolas Bram - 20104278
*	Dennis Thomasen - 20103903
*	Gruppe 3 - Aflevering 3 - Genaflevering
**/

import java.io.*;
import java.net.*;
import java.util.ArrayList;

public class MultiChat {

	private MulticastQueueFifoOnly<String> queue;
	private ArrayList<MulticastMessage> prevMessages;
	private int hasRecieved = 0;

	public MultiChat(String[] args) throws IOException {

		queue = new MulticastQueueFifoOnly<String>();
		prevMessages = new ArrayList<MulticastMessage>();

		if (args.length < 1) {
			queue.createGroup(40303, MulticastQueue.DeliveryGuarantee.FIFO);
			hasRecieved = -1;
		} else {
			String host = args[0];
			
			queue.joinGroup(40303, new InetSocketAddress(host,40303), MulticastQueue.DeliveryGuarantee.FIFO);
			
			PointToPointQueueSenderEndNonRobust<MulticastMessage> sender = new PointToPointQueueSenderEndNonRobust<MulticastMessage>();
			sender.setReceiver(new InetSocketAddress(host,41307));
			sender.put(new MulticastMessageJoin(new InetSocketAddress(InetAddress.getLocalHost().getHostAddress(),41308)));
			
			PointToPointQueueReceiverEndNonRobust<MulticastMessage> reciever = new PointToPointQueueReceiverEndNonRobust<MulticastMessage>();
			reciever.listenOnPort(41308);
			
			MulticastMessage msg;
			while ((msg = reciever.get()) != null) {
				String sender2 = msg.getSender().getAddress().getHostName();
				if (msg instanceof MulticastMessagePayload) {
					String m = ((MulticastMessagePayload<String>)msg).getPayload();
					if (m.equals("LogBegin")) {
						System.out.println("[Begin old messages]");
					} else if (m.equals("LogEnd")) {
						System.out.println("[End of old messages]");
						break;
					} else {
						System.out.println(sender2 + ": " + m);
						prevMessages.add(msg);
					}
				}
				if (msg instanceof MulticastMessageLeave) {
					System.out.println("["+ sender2 + " left the peer to peer group]");
					prevMessages.add(msg);
					
				}
				if (msg instanceof MulticastMessageJoin) {
					System.out.println("["+ sender2 + " joined the peer to peer group]");
					prevMessages.add(msg);
				}
			}
		}
		
		lastMessages oldMessages = new lastMessages(41307, prevMessages);
		oldMessages.start();
		
		InputThread scanner = new InputThread();
		scanner.start();


		MulticastMessage msg;
		while ((msg = queue.get()) != null) {
			prevMessages.add(msg);
			String sender = msg.getSender().getAddress().getHostName();
			if (msg instanceof MulticastMessagePayload) {
				System.out.println(sender + ": " + ((MulticastMessagePayload<String>)msg).getPayload());
			}
			if (msg instanceof MulticastMessageLeave) {
				System.out.println("["+ sender + " left the peer to peer ring]");
				
			}
			if (msg instanceof MulticastMessageJoin) {
				System.out.println("["+ sender + " joined the peer to peer ring]");
			}
		}
	}

	public class lastMessages extends Thread {
		private ArrayList<MulticastMessage> prevMessages;
		private PointToPointQueueReceiverEndNonRobust<MulticastMessage> reciever;
		
		public lastMessages(int port, ArrayList<MulticastMessage> prevMessages) {
			
			this.prevMessages = prevMessages;
			reciever = new PointToPointQueueReceiverEndNonRobust<MulticastMessage>();
			try {
				reciever.listenOnPort(port);
			} catch (IOException e) {}
		}
		
		public void run() {
			MulticastMessage msg;
			
			while ((msg = reciever.get()) != null) {
				if (msg instanceof MulticastMessageJoin) {
					PointToPointQueueSenderEndNonRobust<MulticastMessage> sender = new PointToPointQueueSenderEndNonRobust<MulticastMessage>();
					sender.setReceiver(msg.getSender());
					sender.put(new MulticastMessagePayload(msg.getSender(), new String("LogBegin")));
					for (int i=0; i<prevMessages.size()+hasRecieved; i++) {
						sender.put(prevMessages.get(i));
					}
					sender.put(new MulticastMessagePayload(msg.getSender(), new String("LogEnd")));
				}
			}
		}
	}
	
	public class InputThread extends Thread {
		public void run() {

			try {
				BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
				String line = null;
				while ((line = br.readLine()) != null) {
					if (line.equals("exit")) {
						queue.leaveGroup();
						Thread.sleep(2000);
						System.exit(-1);
					}
					queue.put(line);
				}
			} catch (Exception e) {	}
		}
	}

	public static void main(String[] args) throws IOException {
		new MultiChat(args);
	}



}


